/**
 * FlxCollision
 * 
 * Part of the Flixel Power Tools set
 * 
 * @version 1.1 - April 2nd 2011
 * @link http://www.photonstorm.com
 * @author Richard Davey / Photon Storm
*/

package com.photonstorm.flixel 
{
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.display.BlendMode;
	
	import org.flixel.*;
	
	public class FlxCollision 
	{
		public static var debug:BitmapData = new BitmapData(1, 1, false);
		
		public function FlxCollision() 
		{
		}
		
		/**
		 * A Pixel Perfect Collision check between two FlxSprites.<br />
		 * It will do a bounds check first, and if that passes it will run a pixel perfect match on the intersecting area.<br />
		 * To get it to work with rotated, scaled or animated sprites please use pixelPerfectCheckFP() instead, and read the documentation to go with it.
		 * 
		 * @param	contact			The first FlxSprite to test against
		 * @param	target			The second FlxSprite to test again, sprite order is irrelevant
		 * @param	alphaTolerance	The tolerance value above which alpha pixels are included. Default to 255 (must be fully opaque for collision).
		 * 
		 * @return	Boolean True if the sprites collide, false if not
		 */
		public static function pixelPerfectCheck(contact:FlxSprite, target:FlxSprite, alphaTolerance:int = 255):Boolean
		{
			var boundsA:Rectangle = new Rectangle(contact.x, contact.y, contact.width, contact.height);
			var boundsB:Rectangle = new Rectangle(target.x, target.y, target.width, target.height);
			
			var intersect:Rectangle = boundsA.intersection(boundsB);
			
			if (intersect.isEmpty() || intersect.width == 0 || intersect.height == 0)
			{
				return false;
			}
			
			//	Normalise the values or it'll break the BitmapData creation below
			intersect.x = Math.floor(intersect.x);
			intersect.y = Math.floor(intersect.y);
			intersect.width = Math.ceil(intersect.width);
			intersect.height = Math.ceil(intersect.height);
			
			if (intersect.isEmpty())
			{
				return false;
			}
			
			var testA:BitmapData = contact.pixels;
			var testB:BitmapData = target.pixels;
			
			//	My thanks to Chris Underwood for helping with the translate logic :)
			var matrixA:Matrix = new Matrix;
			matrixA.translate(-(intersect.x - boundsA.x), -(intersect.y - boundsA.y));
			
			var matrixB:Matrix = new Matrix;
			matrixB.translate(-(intersect.x - boundsB.x), -(intersect.y - boundsB.y));
			
			var overlapArea:BitmapData = new BitmapData(intersect.width, intersect.height, false);
			
			overlapArea.draw(testA, matrixA, new ColorTransform(1, 1, 1, 1, 255, -255, -255, alphaTolerance), BlendMode.NORMAL);
			overlapArea.draw(testB, matrixB, new ColorTransform(1, 1, 1, 1, 255, 255, 255, alphaTolerance), BlendMode.DIFFERENCE);
			
			//	Developers: If you'd like to see how this works display it in your game somewhere, or you can comment it out to save a tiny bit of performance
			debug = overlapArea;
			
			var overlap:Rectangle = overlapArea.getColorBoundsRect(0xffffffff, 0xff00ffff);
			overlap.offset(intersect.x, intersect.y);
			
			if (overlap.isEmpty())
			{
				return false;
			}
			else
			{
				return true;
			}
		}
		
		/**
		 * A Pixel Perfect Collision check between two FlxSprites.<br />
		 * Works with rotated, scaled and animated sprites, but requires you to modify the flixel FlxSprite.as file first.<br /><br />
		 * You can either use a patched version of Flixel which is provided in this repository:<br />
		 * flash-game-dev-tips\Flixel Versions\Flixel v2.43 Patch 1.0
		 * <br />
		 * Or you can patch FlxSprite manually by doing the following:<br /><br />
		 * 
		 * 1) At the top of FlxSprite.as is the line:<br />
		 * 
		 * <code>
		 * 		protected var _framePixels:BitmapData;
		 * </code>
		 * 
		 * Change this to be a public var:
		 * 
		 * <code>
		 * 		public var _framePixels:BitmapData;
		 * </code>
		 * 
		 * 2) Un-comment the 2 lines at the start of this function. It will then work.<br /><br />
		 * 
		 * If Adam exposes the frame pixels in a later version of flixel I will update this class accordingly.
		 * 
		 * @param	contact			The first FlxSprite to test against
		 * @param	target			The second FlxSprite to test again, sprite order is irrelevant
		 * @param	alphaTolerance	The tolerance value above which alpha pixels are included. Default to 255 (must be fully opaque for collision).
		 * 
		 * @return	Boolean True if the sprites collide, false if not
		 */
		public static function pixelPerfectCheckFP(contact:FlxSprite, target:FlxSprite, alphaTolerance:int = 255):Boolean
		{
			var testA:BitmapData;
			var testB:BitmapData;
			
			/*
			 * IMPORTANT: For the following 2 lines to work you must have patched your FlxSprite file as detailed above.
			 * It will cause a compiler error otherwise.
			 */
			
			testA = contact._framePixels;
			testB = target._framePixels;
			
			if (!testA || !testB)
			{
				throw Error("No access to FlxSprite._framePixels. Please see documentation in com.photonstorm.flixel.FlxCollision.as");
			}
			
			var boundsA:Rectangle = new Rectangle(contact.x, contact.y, contact.width, contact.height);
			var boundsB:Rectangle = new Rectangle(target.x, target.y, target.width, target.height);
			
			var intersect:Rectangle = boundsA.intersection(boundsB);
			
			if (intersect.isEmpty() || intersect.width == 0 || intersect.height == 0)
			{
				return false;
			}
			
			//	Normalise the values or it'll break the BitmapData creation below
			intersect.x = Math.floor(intersect.x);
			intersect.y = Math.floor(intersect.y);
			intersect.width = Math.ceil(intersect.width);
			intersect.height = Math.ceil(intersect.height);
			
			if (intersect.isEmpty())
			{
				return false;
			}
			
			//	My thanks to Chris Underwood for helping with the translate logic :)
			var matrixA:Matrix = new Matrix;
			matrixA.translate(-(intersect.x - boundsA.x), -(intersect.y - boundsA.y));
			
			var matrixB:Matrix = new Matrix;
			matrixB.translate(-(intersect.x - boundsB.x), -(intersect.y - boundsB.y));
			
			var overlapArea:BitmapData = new BitmapData(intersect.width, intersect.height, false);
			
			overlapArea.draw(testA, matrixA, new ColorTransform(1, 1, 1, 1, 255, -255, -255, alphaTolerance), BlendMode.NORMAL);
			overlapArea.draw(testB, matrixB, new ColorTransform(1, 1, 1, 1, 255, 255, 255, alphaTolerance), BlendMode.DIFFERENCE);
			
			//	Developers: If you'd like to see how this works display it in your game somewhere, or you can comment it out to save a tiny bit of performance
			debug = overlapArea;
			
			var overlap:Rectangle = overlapArea.getColorBoundsRect(0xffffffff, 0xff00ffff);
			overlap.offset(intersect.x, intersect.y);
			
			if (overlap.isEmpty())
			{
				return false;
			}
			else
			{
				return true;
			}
		}
		
	}

}